﻿
using System.Linq;
using System.Linq.Expressions;
using System.Collections.Generic;
using Orchard;
using Orchard.ContentManagement;
using PmpNetwork.Models;
using PmpNetwork.ViewModels;
namespace PmpNetwork.Services
{
    public class QuestionService: IQuestionService
    {
        private readonly IOrchardServices _orchardServices;
        private readonly IContentManager _contentManager;
        public QuestionService(IOrchardServices orchardServices,
            IContentManager contentManager)
        {
            _contentManager = contentManager;
            _orchardServices = orchardServices;
        }

        public IEnumerable<QuestionViewModel> GetQuestionsForArticle(int articleId)
        {
            var questions = _orchardServices.ContentManager.Query<WikiQuestionPart, WikiQuestionPartRecord>()
                .Where(q => q.ArticleId == articleId)
                .OrderBy(q => q.DisplayIndex)
                .List()
                .Select(q =>
                {
                    return new QuestionViewModel()
                    {
                        Id = q.Id,
                        Text = q.Text,
                        ArticleId = q.ArticleId,
                        Reason = q.Reason,
                        DisplayIndex = q.DisplayIndex
                    };
                }).ToDictionary(q => q.Id);

            if (questions.Count == 0) return questions.Values;

            var questionIds = questions.Keys.ToList();

            var currentQuestion = questions.Values.First();

            // get the options and assign to the questions
            var options = _orchardServices.ContentManager.Query<WikiQuestionOptionPart, WikiQuestionOptionPartRecord>()
                .Where(o => questionIds.Contains(o.QuestionId))
                .OrderBy(o => o.QuestionId)
                .List()
                .Select(o => {
                    var option = new QuestionOptionViewModel() { 
                        Id = o.Id,
                        Text = o.Text,
                        QuestionId = o.QuestionId,
                        DisplayIndex = o.DisplayIndex,
                        IsCorrect = o.IsCorrect
                    };

                    if ((currentQuestion == null || currentQuestion.Id != option.QuestionId) && questions.ContainsKey(o.QuestionId))
                    {
                        currentQuestion = questions[o.QuestionId];
                    }

                    if (currentQuestion != null)
                    {
                        if (currentQuestion.Options == null)
                        {
                            currentQuestion.Options = new List<QuestionOptionViewModel>();
                        }

                        currentQuestion.Options.Add(option);
                    }

                    return option;
                })
                .ToList();

            return questions.Values;
        }

        public void SaveQuestions(int articleId, IList<QuestionViewModel> questions)
        {
            List<int> questionsUpdated = new List<int>();
            foreach (var questionVM in questions)
            {
                questionVM.ArticleId = articleId;

                var questionPart = SaveQuestion(questionVM);
                if (questionPart == null) continue;

                questionsUpdated.Add(questionPart.Id);

                if (questionVM.Options != null)
                {
                    List<int> optionsUpdated = new List<int>();
                    foreach (var optionVM in questionVM.Options)
                    {
                        optionVM.QuestionId = questionPart.Id;
                        var optionPart = SaveOption(optionVM);

                        optionsUpdated.Add(optionPart.Id);
                    }

                    // items to delete
                    var optionsToDelete = _contentManager.Query<WikiQuestionOptionPart, WikiQuestionOptionPartRecord>()
                        .Where(o => !optionsUpdated.Contains(o.Id) && o.QuestionId == questionPart.Id)
                        .List()
                        .ToList();

                    foreach (var optionPart in optionsToDelete)
                    {
                        _contentManager.Remove(optionPart.ContentItem);
                    }
                }
            }

            // items to delete
            var questionsToDelete = _contentManager.Query<WikiQuestionPart, WikiQuestionPartRecord>()
                .Where(q => q.ArticleId == articleId && !questionsUpdated.Contains(q.Id))
                .List();

            var questionIdsToDelete = questionsToDelete.Select(q => q.Id).ToList();

            var otherOptionsToDelete = _contentManager.Query<WikiQuestionOptionPart, WikiQuestionOptionPartRecord>()
                .Where(o => questionIdsToDelete.Contains(o.QuestionId))
                .List();

            foreach (var optionPart in otherOptionsToDelete)
            {
                _contentManager.Remove(optionPart.ContentItem);
            }

            foreach (var questionPart in questionsToDelete)
            {
                _contentManager.Remove(questionPart.ContentItem);
            }

            _contentManager.Flush();
        }

        private WikiQuestionPart SaveQuestion(QuestionViewModel questionVM)
        {
            WikiQuestionPart questionPart = null;
            if (questionVM.Id != null)
            {
                questionPart = _contentManager.Get<WikiQuestionPart>(questionVM.Id.Value, VersionOptions.DraftRequired);
                if (questionPart == null) return null;
            }
            else
            {
                questionPart = _contentManager.Create<WikiQuestionPart>("WikiQuestion");
                _contentManager.Create(questionPart, VersionOptions.Draft);
                questionPart.ArticleId = questionVM.ArticleId.Value;
                questionVM.Id = questionPart.Id;
            }

            questionVM.Fill(questionPart);
            _contentManager.Publish(questionPart.ContentItem);

            return questionPart;
        }

        private WikiQuestionOptionPart SaveOption(QuestionOptionViewModel optionVM)
        {
            WikiQuestionOptionPart optionPart = null;
            if (optionVM.Id != null)
            {
                optionPart = _contentManager.Get<WikiQuestionOptionPart>(optionVM.Id.Value, VersionOptions.DraftRequired);
                if (optionPart == null) return null;

            }
            else
            {
                optionPart = _contentManager.Create<WikiQuestionOptionPart>("WikiQuestionOption");
                _contentManager.Create(optionPart, VersionOptions.Draft);
                optionPart.QuestionId = optionVM.QuestionId.Value;

                optionVM.Id = optionPart.Id;
            }
            optionVM.Fill(optionPart);

            _contentManager.Publish(optionPart.ContentItem);

            return optionPart;
        }
    }
}